feat(v0.3): Vue app, CAM-LOG overlay, landing index, shared widgets#1
Merged
feat(v0.3): Vue app, CAM-LOG overlay, landing index, shared widgets#1
Conversation
Ship the first fully working build of RECKIT as a Vue 3 + Vite app. Routes per brand, a live CAM-LOG overlay wired to OBS WebSocket, a landing page index of all browser sources with search and preview, and a shared-widgets split so future brands can drop in audio / readout primitives. - Vue 3 + Vite 6 + Vue Router 4 + obs-websocket-js 5 + sass at src/ - SCSS 7-1 architecture (abstracts / base / layout / components), x25 typo scale, hud-label-base mixin, brand theming via CSS custom properties - Composables: use-obs-websocket (singleton), use-recording-status, use-audio-analyzer, use-scene-name - CAM-LOG at /@kyonax_on_tech/cam-person: HUD frame, dynamic SES::<scene>::T<NN> label, recording timer, audio meter bound to Mic/Aux, live diagnostic readout - Landing page at /: sticky frosted meta bar, brand tabs, responsive 3-column card grid, name/size/tags/requires search filter, status chips, preview modal with canvas-aspect iframe, postMessage trigger buttons - Shared widgets (src/shared/widgets/): audio-meter (self-contained OBS visualizer) and live-readout (text display with refresh_ms throttle) — drop into any brand, theme via --clr-primary-100 - Overlay card: **bold** emphasis markers in descriptions parsed without v-html; use_cases[] keyword tags rendered as chips and included in the search haystack - Version centralization: package.json is canonical; Vite injects __APP_VERSION__ at build time; src/shared/version.js exports VERSION + VERSION_TAG; UI imports VERSION_TAG (no hardcoded v0.x) - .gitignore hardened (editor state, OS junk, secret-file extensions, build caches, !.env.example negation for template) - README + package.json bumped to v0.3; CHANGELOG [v0.3] entry Modified-by: Cristian D. Moreno (Kyonax) <kyonax25@gmail.com>
Protected Files ModifiedThe following protected files were changed in this PR:
Please ensure these changes are intentional and have been reviewed carefully. |
Three CI jobs were failing on the v0.3 release PR. Fix each root cause and improve error reporting so future failures pin to a file and line instead of printing bare messages. ESLint (npm ci failure): - Regenerate package-lock.json against package.json@0.3.0 via `npm install --package-lock-only` (318 packages pinned, 0 vulnerabilities). - Remove package-lock.json from .gitignore. It is now committed; new comment warns not to re-add it. This is what `npm ci` requires. Security Scan (false positive in eslint.config.mjs): - The dangerous-call grep was matching the literal string 'Use DOM APIs instead of document.write().' inside the ESLint rule that *bans* document.write — the rule's own description was tripping the rule. Add --exclude=eslint.config.mjs to the dangerous-pattern scan (the config legitimately documents the banned patterns). - Add --exclude-dir=node_modules/dist/.cache guards so the scan behaves identically whether or not build output exists. - Emit real `::error file=<path>,line=<N>::` annotations per hit so errors pin to the exact source location on the PR diff. Also print human-readable `[category] file:line :: content` lines to the raw log so the failure is obvious without expanding annotations. License Headers (no file path in the raw log): - Echo `[MISSING HEADER] <file>` per hit and print a summary block at the end listing every failing path. Annotations also pin to `line=1` for inline display. - Extend the check to *.vue and *.scss for coverage parity with the rest of the source tree. Headers added to unblock the widened license check: - index.html: MPL block before DOCTYPE (HTML5-safe — comments before DOCTYPE do not trigger quirks mode). - eslint.config.mjs: MPL block prepended so `Cristian D. Moreno` lands on line 2 (was on line 7, outside the first-5-lines window the check reads). - 10 SCSS files (src/app/scss/main.scss + every 7-1 partial): MPL block prepended to each. Verified locally with CI-equivalent filters: dangerous-calls grep clean, license sweep clean, `npm run lint` 0 errors, `npm run build` clean (~980ms). Modified-by: Cristian D. Moreno (Kyonax) <kyonax25@gmail.com>
Protected Files ModifiedThe following protected files were changed in this PR:
Please ensure these changes are intentional and have been reviewed carefully. |
Three independent-but-related improvements to the CI pipeline.
1. Unit-test infrastructure. Vitest wired into the existing
Vite config with happy-dom and @vue/test-utils. Two
initial test files cover the version pipeline
(VERSION / VERSION_TAG derivation) and the overlays
registry schema (required fields, unique ids, status vocab,
use_cases[] type, em-dash ban, path format, canvas dims).
17 tests total. ESLint taught about Vitest globals on
*.test.{js,mjs} / *.spec.{js,mjs} / __tests__/**.
2. Pre-Check Failed label sync. New aggregator job at the
end of ci.yml reads every prior gate's result via needs:
and toggles the GitHub "Pre-Check Failed" label with
`gh pr edit --add-label` / `--remove-label`.
`if: always()` ensures the label syncs even when a prior
gate hard-fails. Requires `issues: write` +
`pull-requests: write` on the workflow, both added to the
top-level permissions block.
3. Broader triggers. Dropped the `branches: [master, dev]`
filter so every pull_request fires CI regardless of
target — a sub-PR into `feat-cam-person` is now gated the
same as a PR into dev. Added a `push` trigger for
feat-* / feat/** / feature/** / fix-* / fix/** branches so
developers get feedback before opening a PR. Concurrency
group keyed on `head_ref || ref` with
`cancel-in-progress: true` dedups push-vs-PR double runs
and cancels stale runs on rapid pushes.
PR template's Testing Coverage section rewritten to the
two-table format (#### Automated tests + #### Quality gates)
so the template reflects the actual post-Vitest state, and
the checklist's "All GitHub Checks have passed" item now
explicitly references the label.
CHANGELOG.org TODO refreshed with an INFRASTRUCTURE > TESTING
follow-up tracking broader coverage (composables, widgets,
landing page computed logic) once the foundation lands.
Verified locally: `npm run lint` 0 errors (6 documented
false-positive warnings), `npm run test` 17 passing,
`npm run build` ~1.0s clean.
Modified-by: Cristian D. Moreno (Kyonax) <kyonax25@gmail.com>
Protected Files ModifiedThe following protected files were changed in this PR:
Please ensure these changes are intentional and have been reviewed carefully. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Checklist (check if it applies)
npm run lint)What does this PR do?
Cuts RECKIT v0.3 — the first end-to-end working build — across three commits on
websocket-cam-person: the Vue 3 + Vite app with the CAM-LOG overlay and landing index, a full CI gate suite (lint, security scan, license headers, unit tests, and aPre-Check Failedlabel sync), and the widget / version / tooling scaffolding that holds it together.Design / Reference: ASCII logo at
.github/assets/logo.txt.Implementation
Bootstrap (
src/)main.js— Vue app mount pointApp.vue— root<router-view />, loads global SCSSrouter.js— brand-routed routes, 404 catchallshared/config.js— frozenOBS_CONFIGfromVITE_*envshared/version.js— exportsVERSION+VERSION_TAGfrom__APP_VERSION__Tests (
src/**/*.test.js)shared/version.test.js— semver shape,VERSION_TAGderivationshared/data/overlays.test.js— registry schema, unique ids, status vocab,use_cases[]type, em-dash banStyles (
src/app/scss/**)src/app/scss/**(10 files) — 7-1 SCSS architecture$colors,$typo-scale(x25 steps, 100–800)hud-label-base,cyberpunk-glowmixins--clr-*CSS custom propertiessrc/app/fonts/SpaceMono/(4 TTFs) — SpaceMono Nerd Font (Regular, Bold, Italic, BoldItalic)Composables (
src/shared/composables/)use-obs-websocket.js— singleton OBSWebSocket, auto-reconnect, subscribes toAll | InputVolumeMetersuse-recording-status.js—RecordStateChanged+ take counter + HH:MM:SS formatteruse-audio-analyzer.js— consumesInputVolumeMeters, defaults toMic/Aux, 8× gain, 16 barsuse-scene-name.js—CurrentProgramSceneChangedComponents (
src/shared/components/)corner-bracket.vue— SVG corner with configurableposition,size,stroke_widthhud-frame.vue— 4 corner brackets + 4 labels + slotoverlay-card.vue— landing card with**bold**emphasis parser,use_cases[]chip tags, 2-col spec gridpreview-modal.vue— iframe scaled to canvas aspect ratio via CSS custom property onwindow.resizerecording-timer.vue— REC + dot turn red while recording; MODE + time stay whitestatus-indicator.vue— blinking dot (red when active, dimmed white otherwise)audio-visualizer.vue— superseded byaudio-meterwidgetWidgets (
src/shared/widgets/)audio-meter.vue— self-contained OBS audio visualizerobs,source_name,bar_countupdate:statewith{ active, source, peak }live-readout.vue— text display with optionalrefresh_mssampling throttleOverlays (
src/brands/kyonax-on-tech/)cam-person.vue— CAM-LOG HUD at/@kyonax_on_tech/cam-personSES::<scene>::T<NN><audio-meter>bound toMic/Aux<live-readout>diagnostic line (WS:… | AUDIO:… | L0:…, 200ms throttle)Overlay registry (
src/shared/data/)overlays.js— CAM-LOG (ready) + ITEM-EXPLAIN (planned) with SHOW / HIDE / CYCLE triggers declaredLanding (
src/views/)home.vue— index with sticky frosted meta bar, brand tabs, responsive 3-col card grid, search + status chips, preview modalRelease
Version: v0.3 (was v0.1)
package.json—"version"bumpREADME.org—#+VERSION:, ASCII logo footer, and shields.io badge bumped tov0.3CHANGELOG.org— new[v0.3]entry; TODO refreshedCI & Tooling
index.html— Vite entry; MPL header added before DOCTYPE (HTML5-safe)vite.config.js— one config for both Vite and Vitestdefine: { __APP_VERSION__ }sourced frompackage.jsonviacreateRequiretest.environment: 'happy-dom',test.globals: true,test.include: src/**/*.{test,spec}.{js,mjs}.github/workflows/ci.yml— complete CI gate pipelinepull_requestruns on every target branch (not justmaster/dev);pushfires onfeat-*/feat/**/feature/**/fix-*/fix/**head_ref || refwithcancel-in-progress: truededups push-vs-PR double runs and kills stale runs on rapid pushesnpm ci(lockfile now tracked); lint runs on**/*.{js,mjs,ts}minusnode_modules/dist--exclude=eslint.config.mjs+--exclude-dir={node_modules,dist,.cache}; emits::error file=,line=::annotations +[category] file:line :: contentlog lines*.vue/*.scss; echoes[MISSING HEADER] <path>per hit + end-of-run summarynpm ci && npm run test(Vitest)if: always(), reads each gate'sresultvianeeds:and toggles thePre-Check FailedGitHub label withgh pr edit --add-label/--remove-labelcontents: read,pull-requests: write,issues: write(required for label sync).gitignore— re-organized by concern; secret-file extension bans (*.pem,*.key,id_rsa*, etc.);!.env.examplenegation;package-lock.jsonun-ignoredeslint.config.mjs—__APP_VERSION__registered as readonly global; Vitest globals (describe,it,test,expect,beforeEach,afterEach,beforeAll,afterAll,vi) enabled on*.test.{js,mjs}/*.spec.{js,mjs}/__tests__/**package.json—test/test:watch/test:coveragescripts.env.example— committed template for the OBS WebSocket varsDependencies
vue@^3.5.13,vue-router@^4.5.0,obs-websocket-js@^5.0.6vite@^6.0.7,@vitejs/plugin-vue@^5.2.1,sass@^1.99.0,vitest@^4.1.4,@vue/test-utils@^2.4.6,happy-dom@^20.9.0package-lock.jsonnow tracked (0 vulnerabilities)Docs
.github/PULL_REQUEST_TEMPLATE.md— structured layout with embedded format rulesTechnical Details
Audio source pipeline
InputVolumeMeterseventgetUserMediagetUserMediadoes not work inside CEF browser sources; OBS gives mixer-accurate levelsReactive state sharing
useObsWebsocketArray reactivity across props boundary
refwith a new array assignment per frameshallowRef+triggerRefshallowRef + triggerRefdoes not propagate to childv-forre-renders across the props boundaryPreview iframe scaling
--iframe-scale) onwindow.resizeResizeObserver-driven reactive computationwindow.resizeVersion string distribution
define: { __APP_VERSION__ }reading frompackage.jsonat config timepackage.jsonautomatically propagates to every UI surface__APP_VERSION__must be declared as a readonly global ineslint.config.mjsand imported viasrc/shared/version.jsSelf-contained widgets vs. primitive components
src/shared/widgets/(self-contained, brand-agnostic drop-ins) andsrc/shared/components/(primitives that still need wiring)shared/components/folder for everything<audio-meter>without learning the analyzer composable APIOverlay description highlighting
**bold**markers parsed into<strong>viaString.prototype.matchAllv-html+ sanitizer / CMS rich-text fieldTesting Coverage
Test runner: Vitest @ 4.1.x with
happy-domand@vue/test-utilsCommand:
npm run testAutomated tests
src/shared/version.test.jsVERSIONsemver shape,VERSION_TAGderivation (v<major>.<minor>)src/shared/data/overlays.test.jsstatusvocab,use_cases[]type,pathformat, canvas dims, no em dashesTotal: 17 tests across 2 files, all passing.
More coverage (composables, widgets, landing computed logic) is tracked as follow-up in CHANGELOG.org under
TODO > INFRASTRUCTURE > TESTING.Quality gates (run on every PR)
eslint.config.mjsvianpm run lintuse-audio-analyzer.js)vite.config.jsvianpm run testvite.config.jsvianpm run build.github/workflows/ci.yml.github/workflows/ci.yml*.js,*.mjs,*.html,*.css,*.vue,*.scssall have MPL headerPre-Check Failedlabelpre-check-labeljob inci.ymlHow to test this PR
Setup
git checkout websocket-cam-person && npm ci && npm run devExpected: Vite boots on
localhost:5173with no errors in stdout..env.exampleto a local env file and populate the OBS WebSocket values.Expected: The local env file is listed as ignored by
git status.Landing page
http://localhost:5173/Expected: Sticky meta bar shows
SOURCES 2 · BRANDS 1 · READY 1 · CANVAS 1920 × 1080 @ 60; header tag readsRECKIT v0.3.Expected: Card grid flows
3 columnson desktop,1 columnon mobile; ASCII logo stays centered.vloginto the search input.Expected: CAM-LOG card matches via its
use_cases[]tags; ITEM-EXPLAIN card is hidden.PLANNEDstatus chip.Expected: Only ITEM-EXPLAIN is visible; the chip dot is brand-gold only on the active chip.
OPENon the CAM-LOG card.Expected: Preview modal opens with the overlay iframe scaled to 16:9; pressing
ESCor clicking outside closes it.COPYon the CAM-LOG card.Expected: URL
http://localhost:5173/@kyonax_on_tech/cam-personis in the clipboard; button flashesCOPIED.CAM-LOG in OBS
http://localhost:5173/@kyonax_on_tech/cam-person, Width1920, Height1080, Custom CSS empty,Shutdown when not visibleOFF,Enable Browser Source Hardware AccelerationON.Expected: HUD renders over transparent background with corner brackets, crosshair, identity block, and toolkit-id visible.
Expected: Top-right HUD label updates to
SES::<newSceneName>::T01.Expected: Timer counts in
HH:MM:SS;RECtext and status dot turn red while recording;MODE:and the time stay white.Expected: Take counter increments to
T02.Expected: Take counter resets to
T01.Mic/Auxinput.Expected: Audio bars respond in real time; debug line reads
WS:ON | AUDIO:Mic/Aux | L0:<nonzero>sampling at 5fps.Expected: Auto-reconnect attempt every 5s;
OFFLINEHUD label appears; debug line readsWS:OFF | AUDIO:NONE | L0:0.Expected: Reads
RECKIT v0.3.CI sanity
npm run lintExpected: 0 errors; 6 known false-positive warnings on
security/detect-object-injectioninuse-audio-analyzer.js.npm run buildExpected: Clean build;
dist/assets/populated.Expected:
ESLint,Security Scan,License Headersall green.Special Deployment Requirements
Mic/Auxinput exists and is unmuted; Desktop Audio and browser-source inputs are skipped automatically.npm cifor reproducible installs; nevernpm installin CI.git tag -a v0.3 -m "RECKIT v0.3" && git push origin v0.3.[v0.3]section ofCHANGELOG.orgas the body.Documentation
DESKTOP — Landing page
MOBILE — Landing page
VIDEO — CAM-LOG overlay running in OBS
SCREENSHOT — Preview modal